/*
 * OREKIT-X
 * Copyright 2002-2008 CS Communication & Systemes
 * 
 * Parts of this software package have been licensed to CS
 * Communication & Systemes (CS) under one or more contributor license
 * agreements.  See the NOTICE file distributed with this work for
 * additional information.
 *  
 * This is an experimental copy of OREKIT from www.orekit.org.
 * Please use the original OREKIT from orekit.org for normal work
 * unrelated to this research project.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License.  You
 * may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied.  See the License for the specific language governing
 * permissions and limitations under the License.
 */
package ore.frames;

import ore.errors.OrekitException;
import ore.time.AbsoluteDate;
import ore.time.TimeScalesFactory;
import ore.time.TimeStamped;

import java.util.Date;

/** 
 * Container class for Earth Orientation Parameters provided by IERS.
 * Instances of this class correspond to lines from either the EOP C
 * 04 yearly files or the Bulletin B monthly files.
 * 
 * @author Luc Maisonobe
 * @author John Pritchard
 */
public class EOP
    extends Object
    implements TimeStamped
{
    /**
     * Dynamic binding of the parametric fields of this class for
     * their interpolation.  
     * @see EOPHistory
     */
    public enum Field {
        poleX, poleY, ut1utc, lod, ddeps, ddpsi;
    }

    public final int mjd;

    public final double poleX, poleY, ut1utc, lod, ddeps, ddpsi;

    private volatile AbsoluteDate date;

    /** 
     */
    public EOP(int mjd, double poleX, double poleY, double ut1utc,
               double lod, double ddeps, double ddpsi)
    {
        super();
        this.mjd    = mjd;
        this.poleX = poleX;
        this.poleY = poleY;
        this.ut1utc = ut1utc;
        this.lod = lod;
        this.ddeps = ddeps;
        this.ddpsi = ddpsi;
    }


    /**
     * Get the entry date (modified julian day, 00h00 UTC scale).
     * @return Entry date
     * @see #getDate()
     */
    public final int getMjd() {
        return mjd;
    }
    /**
     * @return Entry date
     * @see #getMjd()
     * @exception OrekitException UTC scale cannot be initialized by
     * the time scales factory.
     */
    public final AbsoluteDate getDate(){
        AbsoluteDate date = this.date;
        if (null == date){
            long D = (this.mjd - 40587L) * 86400000L;
            date = new AbsoluteDate(new Date(D), TimeScalesFactory.getUTC());
            this.date = date;
        }
        return date;
    }
    public final double getPoleX() {
        return this.poleX;
    }
    public final double getPoleY() {
        return this.poleY;
    }
    public final double getUt1utc() {
        return this.ut1utc;
    }
    public final double getLod() {
        return this.lod;
    }
    public final double getDdeps() {
        return this.ddeps;
    }
    public final double getDdpsi() {
        return this.ddpsi;
    }
    public final double get(Field field){
        switch (field){
        case poleX:
            return this.poleX;
        case poleY:
            return this.poleY;
        case ut1utc:
            return this.ut1utc;
        case lod:
            return this.lod;
        case ddeps:
            return this.ddeps;
        case ddpsi:
            return this.ddpsi;
        default:
            throw new IllegalStateException();
        }
    }
    public final int compareTo(TimeStamped stamped) {
        return this.getDate().compareTo(stamped);
    }
    public int hashCode(){
        return this.mjd;
    }
    public boolean equals(Object that){
        if (that == this)
            return true;
        else if (that instanceof EOP)
            return ( ((EOP)that).mjd == this.mjd);
        else
            return false;
    }
}
